package com.hai.qtalk.base;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Iterator;

import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hai.qtalk.bean.User;
import com.hai.qtalk.service.UserService;

public class SocketServer implements Runnable {

	private boolean running;// 表示服务器是否在运行

	private Selector selector;
	private String writeMsg;
	private StringBuffer sb = new StringBuffer();
	private SelectionKey ssckey;
	private static boolean isStart = false;// 测试用，用于表示服务器开始接收服务请求，可测试从服务器每秒接收多少请求
	private SelectionKeyMap map;

	private static Logger log = LoggerFactory.getLogger(SocketServer.class);

	public SocketServer() {
		running = true;
		map = SelectionKeyMap.getInstance();
	}

	public void init() {
		try {
			selector = Selector.open();
			ServerSocketChannel ssc = ServerSocketChannel.open();
			ssc.configureBlocking(false);
			ssc.socket().bind(new InetSocketAddress(2345));
			ssckey = ssc.register(selector, SelectionKey.OP_ACCEPT);
			log.debug("server is starting... {}", new Date());
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	// public static void main(String[] args) throws InterruptedException {
	// MySocketServer server = new MySocketServer();
	// new Thread(server).start();
	// while(!isStart);
	// Thread.sleep(1000);
	// log.debug("已成功建立客户端连接的数量 {}",Counter.getClientConnectCount());
	// log.debug("已接收到客户端发送消息的数量 {}",Counter.getClientSendMessageCount());
	// log.debug("已发送给客户端消息的数量 {}",Counter.getClientReceiveMessageCount());
	// // System.out.println("已成功建立客户端连接的数量"+Counter.getClientConnectCount());
	// //
	// System.out.println("已接收到客户端发送消息的数量"+Counter.getClientSendMessageCount());
	// //
	// System.out.println("已发送给客户端消息的数量"+Counter.getClientReceiveMessageCount());
	// }

	public void execute() {
		try {
			while (running) {
				int num = selector.select();
				if (num > 0) {
					Iterator<SelectionKey> it = selector.selectedKeys()
							.iterator();
					while (it.hasNext()) {
						SelectionKey key = it.next();
						it.remove();
						if (!key.isValid()){
							key.cancel();
							continue;
						}	
						if (key.isAcceptable()) {
							isStart = true;
							getConn(key);
						} else {
							if (key.isReadable()) {
								readMsg(key);
							}
							if (key.isValid()&&key.isWritable()) {
								writeMsg(key);
							}
						}
					}
				}
				Thread.yield();// 放弃占用CPU，与 其他线程一起重新竞争CPU
			}
		}catch (CancelledKeyException cx) {
			cx.printStackTrace();
		}
		catch (IOException ex) {
			ex.printStackTrace();
		}
		
	}

	private void getConn(SelectionKey key) throws IOException {
		ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
		SocketChannel sc = ssc.accept();
		sc.configureBlocking(false);
		Counter.AddClientConnectCount();
		sc.register(selector, SelectionKey.OP_READ);

		System.out.println("build connection :"
				+ sc.socket().getRemoteSocketAddress());
	}

	private void readMsg(SelectionKey key) throws IOException {
		sb.delete(0, sb.length());
		SocketChannel sc = (SocketChannel) key.channel();
		// System.out.print(sc.socket().getRemoteSocketAddress() + " ");
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		buffer.clear();
		int len =0;
		while ((len = sc.read(buffer)) > 0) {

		}
		if(len==-1){
			key.channel().close();
			key.cancel();
			return ;
		}
		buffer.flip();
		String transObjectString = new String(buffer.array(), "utf-8");
		System.out.println("收到消息" + transObjectString);
		if (transObjectString != null && !("".equals(transObjectString.trim()))) {
			String temp[] = transObjectString.split("\\|");
			Integer type = null;
			if(temp[0]!=null&&!"".equals(temp[0]))
			type = Integer.parseInt(temp[0]);// 消息类型
			// if(!"4".equals(type)){//非登录操作
			// Integer fromUserID = Integer.parseInt(temp[1]);//发送方ID
			// String fromUserName = temp[2];//发送方名称
			// Integer toUserID = Integer.parseInt(temp[3]);//接收方ID
			// StringBuilder content = null;//消息内容
			// int i=4;
			// while(i < temp.length){
			// content.append(temp[i]);
			// }
			// }

			switch (type) {
			case 1:// 大厅消息
				for (SelectionKey allOut : map.getAll()) {
					allOut.attach(transObjectString);
					writeMsg(allOut);
//					allOut.interestOps(SelectionKey.OP_WRITE);
				}
				log.info("当前服务器维护socket数量:{}", map.size());
				break;
			case 2:// 私信消息，一对一
				SelectionKey toUser = map.getById(Integer.parseInt(temp[3]));// temp[3]为接收方ID
				if (toUser != null) {
					toUser.attach(transObjectString);
					writeMsg(toUser);
//					toUser.interestOps(SelectionKey.OP_WRITE);
				} else {
					TransObject text = new TransObject();
					text.setType(2);
					text.setContent("对方不在线，请过会再联系。 ");
					text.setFromUserID(0);// 0表示系统消息
					key.attach(text.toString());
					writeMsg(key);
//					key.interestOps(SelectionKey.OP_WRITE);
				}
				break;
			case 3:// REFRESH
					// List<User> refreshList = dao.refresh(read_tranObject
					// .getFromUser());
					// TranObject<List<User>> refreshO = new
					// TranObject<List<User>>(
					// TranObjectType.REFRESH);
					// refreshO.setObject(refreshList);
					// out.setMessage(refreshO);
				break;
			case 4:// LOGIN
				Integer loginId = Integer.parseInt(temp[1]);
				String pwd = temp[2].trim();
				System.out.println("ID:" + loginId + " pwd:" + pwd);
				UserService us = new UserService();
				JSONObject json = null;
				TransObject msg = new TransObject();
				msg.setType(4);
				if ((json = us.login(loginId.intValue(), pwd)) != null) {
					// 将该用户ID及其对应的写线程存入缓存map中,如果已存在则移除，重新加入
					if (map.getById(loginId) != null) {
						map.remove(loginId);
					}
					map.add(loginId, key);
					log.info("当前在线人数" + map.size());
					System.out.println("当前在线人数" + map.size());
					// 设置要发送的消息内容
					msg.setContent(json.toString());
				} else {
					msg.setContent("");
				}
				key.attach(msg.toString());
				writeMsg(key);
//				key.interestOps(SelectionKey.OP_WRITE);
				break;
			case 5:// LOGOUT

				break;
			case 6:// REGISTER
				String registerName = temp[1];// nickname
				String registerPwd = temp[2];// password
				// 将新注册用户写入数据库
				User u = new User(registerName, registerPwd);
				UserService uRegister = new UserService();
				long registerId = uRegister.addUser(u);
				// 返回注册信息
				TransObject registerMsg = new TransObject();
				registerMsg.setContent("" + registerId);
				key.attach(registerMsg.toString());
				writeMsg(key);
//				key.interestOps(SelectionKey.OP_WRITE);
				break;
			default:
				selector.wakeup();
				break;

			}
		}
	}

	public void run() {
		init();
		execute();
	}

	private void writeMsg(SelectionKey key) throws IOException {
		SocketChannel sc = (SocketChannel) key.channel();
		String str = (String)key.attachment();
		System.out.println("发送消息："+str);
		if (str != null) {
			sc.write(ByteBuffer.wrap(str.getBytes(Charset.forName("UTF-8"))));
		}
//		key.interestOps(SelectionKey.OP_READ); // 写完将该key的关注事件改为读事件
	}

	public void quit() {
		try {
			selector.close();
		} catch (IOException e) {

			e.printStackTrace();
		}

	}
}
